/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package livraria.objects;

import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;

import livraria.database.Conexao;
import livraria.database.exceptions.RegistroNaoEncontradoException;
import livraria.utils.enums.CategEnum;
import livraria.database.DBUtils;
import livraria.database.exceptions.ErroDatabaseException;
import livraria.database.exceptions.ValorJaExisteException;

/**
 *
 * @author Ivanovikjch
 */
public class Livro {
    //Dados do livro
    private int codigo, ano;
    private String nome;
    private CategEnum categoria;
    
    //Lista de nomes e codigos dos autores do livro
    private HashMap<Integer, String> nomes_autores;
    private ArrayList<Integer> codigos_autores;
    
    //Dados de estoque
    private int NumeroItens;
    private boolean OperacaoEntrada;
    
    //Dados de valores
    private float valor;
    private Date data_valor;
    
    //Dado de controle de database, se for true , o objeto ja esta salvo na database
    private boolean ValorRegistrado;
    
    public Livro(int codigo, int ano, String nome, CategEnum categoria, HashMap<Integer, String>  nomes_autores, ArrayList<Integer> codigos_autores, int NumeroItens, boolean OperacaoEntrada, float Valor, Date data_valor){
        this(codigo, ano, nome, categoria, nomes_autores, codigos_autores, NumeroItens, OperacaoEntrada, Valor, data_valor, false);
    }
    public Livro(int codigo, int ano, String nome, CategEnum categoria, HashMap<Integer, String>  nomes_autores, ArrayList<Integer> codigos_autores, int NumeroItens, boolean OperacaoEntrada, float Valor, Date data_valor, boolean ValorRegistrado){
        this.codigo = codigo;
        this.ano = ano;
        this.nome = nome;
        this.categoria = categoria;
        this.nomes_autores = nomes_autores;
        this.codigos_autores = codigos_autores;
        this.NumeroItens = NumeroItens;
        this.OperacaoEntrada = OperacaoEntrada;
        this.valor = Valor;
        this.data_valor = data_valor;
        this.ValorRegistrado = ValorRegistrado;
    }
    
    //Metodos para obtencao e alteracao de valores
    public int getCodigo(){return codigo;}
    public int getAno(){return ano;}
    public String getNome(){return nome;}
    public CategEnum getCategoria(){return categoria;}
    public int getNumeroItens(){return NumeroItens;}
    public boolean getOperacaoEntrada(){return OperacaoEntrada;}
    public float getValor(){return valor;}
    public Date getData_valor(){return (Date)data_valor.clone();}
    
    public void setCodigo(int codigo){this.codigo=codigo;}
    public void setAno(int ano){this.ano=ano;}
    public void setNome(String nome){this.nome=nome;}
    public void setCategoria(CategEnum categoria){this.categoria=categoria;}
    public void setNumeroItens(int NumeroItens){this.NumeroItens=NumeroItens;}
    public void setOperacaoEntrada(boolean OperacaoEntrada){this.OperacaoEntrada=OperacaoEntrada;}
    public void setValor(float Valor){this.valor=Valor;}
    public void setData_valor( Date Data_valor){this.data_valor=Data_valor;}
    
    
    //Retorna todos os objetos dos autores em uma lista
    public ArrayList<Autor> getAutoresObjects() throws RegistroNaoEncontradoException, SQLException{
        ArrayList<Autor> autores = new ArrayList<Autor>();
        for(int id : codigos_autores)
            autores.add(DBUtils.getAutorByCodigo(id));
        return autores;
    }
    
    public void insertNewAutor(int codigo) throws ErroDatabaseException, ValorJaExisteException{
        try {
            PreparedStatement stm = Conexao.conecta().prepareStatement("SELECT nome FROM autores WHERE codigo = ?");
            stm.setInt(1, codigo);
            ResultSet rs = stm.executeQuery();
            //stm.close();
            if(!rs.next())
                throw new RegistroNaoEncontradoException(); //TODO: criar exceçao nova
            String nome_autor = rs.getString("nome");
            rs.close();
            stm.close();
            for(int id : codigos_autores){
                if(codigo == id)
                    throw new ValorJaExisteException();
            }
            stm = Conexao.conecta().prepareStatement("INSERT INTO autor_livro VALUES(?, ?)");
            stm.setInt(1, codigo);
            stm.setInt(2, this.codigo);
            int alteracoes = stm.executeUpdate();
            if(alteracoes == 0) 
                throw new ErroDatabaseException();
            codigos_autores.add(codigo);
            this.nomes_autores.put(codigo, nome_autor);
        } catch (SQLException ex) {
            throw new ErroDatabaseException();
        }  
    }
    
    //Metodos de insercao na database
    private void insert() throws ErroDatabaseException{
        try {
            PreparedStatement stm = Conexao.conecta().prepareStatement("INSERT INTO livros VALUES(?, ?, ?, ?)");
            stm.setInt(1, codigo);
            stm.setString(2, nome);
            stm.setInt(3, ano);
            stm.setString(4, categoria.categString());
            int alteracoes = stm.executeUpdate();
            if(alteracoes == 0) 
                throw new ErroDatabaseException();
            stm.close();
            stm = Conexao.conecta().prepareStatement("INSERT INTO estoque VALUES(?, ?, ?)");
            stm.setInt(1, codigo);
            stm.setInt(2, NumeroItens);
            stm.setBoolean(3, OperacaoEntrada);
            alteracoes = stm.executeUpdate();
            if(alteracoes == 0) 
                throw new ErroDatabaseException();
            stm.close();
            stm = Conexao.conecta().prepareStatement("INSERT INTO valores VALUES(?, ?, ?)");
            stm.setInt(1, codigo);
            stm.setDate(2, new java.sql.Date(data_valor.getTime()));
            stm.setFloat(3, valor);
            alteracoes = stm.executeUpdate();
            if(alteracoes == 0) 
                throw new ErroDatabaseException();
            stm.close();
            
        } catch (SQLException ex) {
            throw new ErroDatabaseException();
        }
    }
    private void update() throws ErroDatabaseException{
        try {
            PreparedStatement stm = Conexao.conecta().prepareStatement("UPDATE livros SET nome = ?, ano = ?, categoria = ? WHERE codigo = ?");
            stm.setString(1, nome);
            stm.setInt(2, ano);
            stm.setString(3, categoria.categString());
            stm.setInt(4, codigo);
            int alteracoes = stm.executeUpdate();
            if(alteracoes == 0) 
                throw new ErroDatabaseException();
            stm.close();
            PreparedStatement stm2 = Conexao.conecta().prepareStatement("UPDATE estoque SET nitens = ?, operacao = ? WHERE livro = ?");
            stm2.setInt(3, codigo);
            stm2.setInt(1, NumeroItens);
            stm2.setBoolean(2, OperacaoEntrada);
            alteracoes = stm2.executeUpdate();
            if(alteracoes == 0) 
                throw new ErroDatabaseException();
            stm2.close();
            stm = Conexao.conecta().prepareStatement("UPDATE valores SET data = ?, valor = ? WHERE livro = ?");
            stm.setInt(3, codigo);
            stm.setDate(1, new java.sql.Date(data_valor.getTime()));
            stm.setFloat(2, valor);
            alteracoes = stm.executeUpdate();
            if(alteracoes == 0) 
                throw new ErroDatabaseException();
            stm.close();
            
        } catch (SQLException ex) {
            throw new ErroDatabaseException();
        }
    }
    //Metodo de salvar que sera usado.
    public void save() throws ErroDatabaseException{
        if(this.ValorRegistrado)
            update();
        else
            insert();
        
        this.ValorRegistrado = true;
    }

    public ArrayList<Integer> getCodigos_autores() {
        return this.codigos_autores;
    }

    public HashMap<Integer, String> getNomes_autores() {
        return this.nomes_autores;
    }
    
}
